/*********************
* Author:Dzlua
* QQ:505544956
* time:2016/12/17
*/
#include "Animation.h"
#include "../edui.h"

EDUI_NAMESPACE_BEGIN

#ifdef EDUI_TEST_NEW_DELETE
int Animation::m_newdeleteNum = 0;
int Animation::_GetNewDeleteNum()
{
    return m_newdeleteNum;
}
#endif

Animation* Animation::GetInterface()
{
    Animation* animation = new Animation;
#ifdef EDUI_TEST_NEW_DELETE
    ++m_newdeleteNum;
    Log("[Animation] new animation %d", animation);
#endif
#ifdef EDUI_USE_LUAPLUS
    LuaMgrPtr->Add("Animation", animation);
#endif
    return animation;
}

void Animation::Release()
{
#ifdef EDUI_TEST_NEW_DELETE
    --m_newdeleteNum;
    Log("[Animation] delete animation %d", this);
#endif
#ifdef EDUI_USE_LUAPLUS
    LuaMgrPtr->Remove(this);
#endif
    delete this;
}

Animation::Animation() : m_wnd(0), m_frames(0), m_ctrls(0), m_curFrame(0), m_timer(0)
{
    m_frames = new MgrSimple<AnimationFrame>;
    m_ctrls = new MgrSimple<Control>;
}

Animation::~Animation()
{
    this->Destroy();
    if (m_frames){
        delete m_frames;
        m_frames = 0;
    }

    if (m_ctrls){
        delete m_ctrls;
        m_ctrls = 0;
    }
}

void Animation::Destroy()
{
    for (size_t i = 0; i < m_frames->Count(); ++i){
        AnimationFrame* frame = m_frames->GetByIndex(i);
        if (frame){
            delete frame;
        }
    }
    m_frames->Clear();

    m_ctrls->Clear();

    if (m_wnd){
        if (m_timer){
            m_wnd->RemoveTimer(m_timer);
            m_timer = 0;
        }
        m_wnd = 0;
    }
}

bool Animation::IsOK()
{
    return !!m_wnd;
}

bool Animation::Create(IWindow* wnd, const char* name, int id)
{
    if (!wnd) return false;

    m_wnd = wnd;

    AnimationMgr* mgr = wnd->GetAnimationMgr();
    if (!mgr->Add(name, this, id)){
        this->Destroy();
        return false;
    }
    return true;
}

bool Animation::AddFrame(const char* img, int id)
{
    if (!m_wnd || !img) return false;
    ITexture* texture = m_wnd->FindTexture(img, true);
    if (!texture) return false;

    int num = texture->GetNum();
    for (int i = 0; i < num; ++i){
        Point pt = texture->GetOffset(i);
        Size sz = texture->GetSize(i);
        AnimationFrame *tmp = new AnimationFrame;
        tmp->texture = texture;
        tmp->id = i;
        tmp->x = pt.x;
        tmp->y = pt.y;
        tmp->w = sz.w;
        tmp->h = sz.h;
        tmp->delay = texture->GetDelay(i);
        if (id < 0) m_frames->Add(tmp);
        else m_frames->AddAt(tmp, id + i);
    }
    return true;
}

bool Animation::AddFrame(int imgid, int id)
{
    if (!m_wnd || !imgid) return false;
    ITexture* texture = m_wnd->FindTexture(imgid, true);
    if (!texture) return false;

    int num = texture->GetNum();
    for (int i = 0; i < num; ++i){
        Point pt = texture->GetOffset(i);
        Size sz = texture->GetSize(i);
        AnimationFrame *tmp = new AnimationFrame;
        tmp->texture = texture;
        tmp->id = i;
        tmp->x = pt.x;
        tmp->y = pt.y;
        tmp->w = sz.w;
        tmp->h = sz.h;
        tmp->delay = texture->GetDelay(i);
        if (id < 0) m_frames->Add(tmp);
        else m_frames->AddAt(tmp, id + i);
    }
    return true;
}

bool Animation::AddFrame(AnimationFrame* frame, int id)
{
    if (!frame || !frame->texture) return false;
    AnimationFrame *tmp = new AnimationFrame;
    tmp->texture = frame->texture;
    tmp->id = 0;
    tmp->x = frame->x;
    tmp->y = frame->y;
    tmp->w = frame->w;
    tmp->h = frame->h;
    tmp->delay = frame->delay;
    if (id == -1) m_frames->Add(tmp);
    else m_frames->AddAt(tmp, id);
    return true;
}

void Animation::RemoveFrame(int id)
{
    m_frames->Remove(m_frames->GetByIndex(id));
}

void Animation::RemoveFrame(AnimationFrame* frame)
{
    m_frames->Remove(frame);
}

size_t Animation::FrameCount()
{
    return m_frames->Count();
}

//control will Invaldate
void Animation::AddNotify(Control* ctrl)
{
    m_ctrls->Add(ctrl);
}

void Animation::RemoveNotify(Control* ctrl)
{
    m_ctrls->Remove(ctrl);
}

size_t Animation::NotifyCount()
{
    return m_ctrls->Count();
}

Uint32 Animation_TimerCallback(TimerID id, Uint32 interval, IWindow* wnd, void *data1, void *data2)
{
    Animation* pthis = (Animation*)data1;
    if (!pthis) return 0;
    pthis->Notify(true);
    AnimationFrame* frame = pthis->GetCurFrame();
    if (!frame) return 0;

    return frame->delay;
}

void Animation::Start(int interval)
{
    if (m_wnd){
        if (m_timer) m_wnd->RemoveTimer(m_timer);
        m_timer = m_wnd->AddTimer(interval, Animation_TimerCallback, this);
    }
}

void Animation::Stop()
{
    if (m_wnd && m_timer){
        m_wnd->RemoveTimer(m_timer);
        m_timer = 0;
    }
}

bool Animation::IsRun()
{
    return !!m_timer;
}

void Animation::Reset()
{
    this->Stop();
    m_curFrame = 0;
}

AnimationFrame* Animation::GetFrame(int id)
{
    return m_frames->GetByIndex(id);
}

AnimationFrame* Animation::GetCurFrame()
{
    return m_frames->GetByIndex(m_curFrame);
}

void Animation::Notify(bool bAddFrame)
{
    for (size_t i = 0; i < m_ctrls->Count(); ++i){
        Control* ctrl = m_ctrls->GetByIndex(i);
        if (ctrl){
            ctrl->Invaldate();
        }
    }

    if (bAddFrame){
        size_t count = this->FrameCount();
        m_curFrame++;
        if (m_curFrame >= count) m_curFrame = 0;
    }
}

EDUI_NAMESPACE_END
